#ifndef __SYLAR_SCHEDULER_H__
#define __SYLAR_SCHEDULER_H__

#include <memory>
#include <vector>
#include <list>
#include "fiber.h"
#include "thread.h"

namespace sylar {

class Scheduler {
public:
  typedef std::shared_ptr<Scheduler> ptr;
  typedef Mutex MutexType;

  Scheduler(size_t threads = 1, bool use_caller = true, const std::string& name = "");
  virtual ~Scheduler();

  const std::string& getName() const { return m_name; }

  static Scheduler* GetThis();
  static Fiber* GetMainFiber();

  void start();
  void stop();

  template<class FiberOrCb>
  void schedule(FiberOrCb fc, int thread = -1) {
    bool need_tickle = false;
    {
      MutexType::Lock lock(m_mutex);
      need_tickle = schedulerNoLock(fc, thread);
    }
    if (need_tickle) {
      tickle();
    }
  }

  template<class InputIterator>
  void schedule(InputIterator begin, InputIterator end) {
    bool need_tickle = false;
    {
      MutexType::Lock lock(m_mutex);
      while (begin != end) {
        need_tickle = schedulerNoLock(&*begin) || need_tickle;
      }
    }
    if (need_tickle) {
      tickle();
    }
  }
protected:
  virtual void tickle();
  void run();
  virtual bool stopping();
  virtual void idle();
  void setThis();
private:
  template<class FiberOrCb>
    bool schedulerNoLock(FiberOrCb fc, int thread) {
      bool need_tickle = m_fibers.empty();
      FiberAndThread ft(fc, thread);
      if (ft.fiber || ft.cb) {
        m_fibers.push_back(ft);
      }
      return need_tickle;
    }
private:
  struct FiberAndThread {
    Fiber::ptr fiber;
    std::function<void()> cb;
    int thread;

    FiberAndThread(Fiber::ptr f, int thr)
      : fiber(f), thread(thr) {
    }

    FiberAndThread(Fiber::ptr* f, int thr)
      : thread(thr) {
      fiber.swap(*f);
    }

    FiberAndThread(std::function<void()> f, int thr)
      : cb(f), thread(thr) {
    }
    
    FiberAndThread(std::function<void()>* f, int thr)
      : thread(thr) {
      cb.swap(*f);
    }

    FiberAndThread() : thread(-1) {}

    void reset() {
      fiber = nullptr;
      cb = nullptr;
      thread = -1;
    }
  };
private:
  // 互斥量
  MutexType m_mutex;
  // 线程池
  std::vector<Thread::ptr> m_threads;
  // 协程链表
  std::list<FiberAndThread> m_fibers;
  // 主协程
  Fiber::ptr m_rootFiber;
  std::string m_name;
protected:
  // 线程池中的线程 id
  std::vector<int> m_threadIds;
  // 线程数量
  size_t m_threadCount;
  // 已经使用的线程数量
  std::atomic<size_t> m_activeThreadCount = {0};
  // 空闲状态的线程数量
  std::atomic<size_t> m_idleThreadCount = {0};
  bool m_stopping = true;
  bool m_autoStop = false;
  int m_rootThread = 0;
};

}

#endif
